package com.roadjava.rbac.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.roadjava.rbac.bean.dto.SecurityUserDTO;
import com.roadjava.rbac.bean.entity.AuthorityDO;
import com.roadjava.rbac.bean.entity.LinkUserRoleDO;
import com.roadjava.rbac.bean.entity.UserDO;
import com.roadjava.rbac.bean.req.user.*;
import com.roadjava.rbac.bean.res.Result;
import com.roadjava.rbac.bean.vo.OnlineUserVO;
import com.roadjava.rbac.bean.vo.UserRouteMetaVO;
import com.roadjava.rbac.bean.vo.UserRouteVO;
import com.roadjava.rbac.bean.vo.UserVO;
import com.roadjava.rbac.constants.CommonConstants;
import com.roadjava.rbac.ex.BizEx;
import com.roadjava.rbac.service.AuthorityService;
import com.roadjava.rbac.service.LinkRoleAuthorityService;
import com.roadjava.rbac.service.LinkUserRoleService;
import com.roadjava.rbac.service.UserService;
import com.roadjava.rbac.mapper.UserMapper;
import com.roadjava.rbac.util.ConvertUtil;
import com.roadjava.rbac.util.SortableTreeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 针对表【user(用户表)】的数据库操作Service实现
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService{

    @Resource
    private LinkUserRoleService linkUserRoleService;
    @Resource
    private LinkRoleAuthorityService linkRoleAuthorityService;
    @Resource
    private AuthorityService authorityService;
    @Autowired
    private UserMapper userMapper;

    @Override
    public UserVO queryById(Long id) {
        UserDO entity = getById(id);
        return ConvertUtil.convert(entity,UserVO.class);
    }
    @Override
    public void updateUserInfo(UserUpdateReq2 user) {
        userMapper.updateUserInfo(user.getId(), user.getRealName(), user.getEmail(), user.getPhone(), user.getSex());
    }

    @Override
    public Long postRoleByUser(long id) {
        // 查询用户拥有的角色
        Long roleId = userMapper.postRole(id); // 获取角色 ID
        return roleId; // 直接返回角色 ID，也可能为 null
    }

    @Override
    public List<UserDO> getList(UserDO user) {
        return userMapper.emptyList();
    }

    @Override
    public List<OnlineUserVO> queryUserOnline() {
        List<UserDO> userList = userMapper.selectList(new QueryWrapper<>());
        List<OnlineUserVO> onlineUserVOS = new ArrayList<>();
        for (UserDO user : userList) {
            OnlineUserVO onlineUserVO = new OnlineUserVO();
            onlineUserVO.setId(user.getId());
            onlineUserVO.setUsername(user.getUsername());
            onlineUserVO.setAvatarPath(user.getAvatarPath());
            onlineUserVOS.add(onlineUserVO);
        }
        return onlineUserVOS;

    }


    @Override
    public UserDetails loadUserByUsername(String username) {
        LambdaQueryWrapper<UserDO> lqw = Wrappers.<UserDO>lambdaQuery()
                .eq(UserDO::getUsername,username);
        UserDO one = getOne(lqw);
        if (one == null) {
            throw new BizEx("账号信息不存在");
        }
        // 查询用户权限信息
        List<AuthorityDO> userAuthorities = queryUserAuthorities(one.getId());
        Set<String> backAuthorizedUris = toBackAuthorizedUris(userAuthorities);
        List<UserRouteVO> userRoutes = toUserRoutes(userAuthorities);
        SecurityUserDTO dto = new SecurityUserDTO();
        dto.setUserDO(one);
        dto.setBackAuthorizedUris(backAuthorizedUris);
        dto.setUserRoutes(userRoutes);
        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyById(UserUpdateReq updateReq) {
        LambdaUpdateWrapper<UserDO> luw = new LambdaUpdateWrapper<>();
        luw.set(UserDO::getRealName,updateReq.getRealName())
                .set(UserDO::getSex,updateReq.getSex())
                .set(UserDO::getAvatarPath,updateReq.getAvatarPath())
                .eq(UserDO::getId,updateReq.getId())
                .set(UserDO::getEmail,updateReq.getEmail())
                .set(UserDO::getPhone,updateReq.getPhone());

        update(luw);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePwd(UpdatePwdReq updatePwdReq) {
        UserDO existedEntity = getById(updatePwdReq.getId());
        if (existedEntity == null) {
            throw new BizEx("用户不存在");
        }
        PasswordEncoder passwordEncoder = SpringUtil.getBean(PasswordEncoder.class);
        if(!passwordEncoder.matches(updatePwdReq.getOriginalPwd(),existedEntity.getPwd())) {
            throw new BizEx("原始密码不正确");
        }
        existedEntity.setPwd(passwordEncoder.encode(updatePwdReq.getNewPwd()));
        updateById(existedEntity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(UserAddReq addReq) {
        UserDO entity = ConvertUtil.convert(addReq, UserDO.class);
        PasswordEncoder passwordEncoder = SpringUtil.getBean(PasswordEncoder.class);
        // 加密密码
        entity.setPwd(passwordEncoder.encode(entity.getPwd()));
        save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {
        // 删除用户和角色关联表中的数据
        linkUserRoleService.deleteByUserId(id);
        // 删除用户
        removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignRole(AssignRoleReq assignRoleReq) {
        // 删除用户和角色关联表中的数据
        linkUserRoleService.deleteByUserId(assignRoleReq.getUserId());
        // 保存关联关系
        List<LinkUserRoleDO> list = assignRoleReq.getRoleIds().stream()
                .map(roleId -> {
                    // 同名属性赋值
                    LinkUserRoleDO entity = ConvertUtil.convert(assignRoleReq, LinkUserRoleDO.class);
                    entity.setRoleId(roleId);
                    return entity;
                }).collect(Collectors.toList());
        linkUserRoleService.saveBatch(list);
    }

    @Override
    public Result<List<UserVO>> queryPage(UserPageReq pageReq) {
        Long count = getBaseMapper().queryCount(pageReq);
        if (count.equals(0L)) {
            return Result.buildSuccess(Collections.emptyList(),count);
        }
        List<UserVO> vos = getBaseMapper().queryList(pageReq);
        return Result.buildSuccess(vos,count);
    }

    @Override

    public void register(UserRegisterReq registerReq) {
        PasswordEncoder passwordEncoder = SpringUtil.getBean(PasswordEncoder.class);
        registerReq.setPwd(passwordEncoder.encode(registerReq.getPwd()));
        System.out.println(registerReq.getPwd());
        System.out.println(registerReq.getReal_name());
        System.out.println(registerReq.getSex());
        userMapper.addUser(registerReq.getUsername(), registerReq.getPwd(), registerReq.getReal_name(),registerReq.getSex());
    }



    /**
     * 转为路由
     */
    private List<UserRouteVO> toUserRoutes(List<AuthorityDO> userAuthorities) {
        if (CollUtil.isEmpty(userAuthorities)) {
            return Collections.emptyList();
        }
        // 此时是无序的列表
        Set<UserRouteVO> set = userAuthorities.stream()
                .map(authority -> {
                    UserRouteVO userRouteVo = ConvertUtil.convert(authority, UserRouteVO.class);
                    UserRouteMetaVO userRouteMetaVo = ConvertUtil.convert(authority, UserRouteMetaVO.class);
                    userRouteVo.setMeta(userRouteMetaVo);
                    return userRouteVo;
                }).collect(Collectors.toSet());
        return SortableTreeUtil.buildTree(set);
    }

    /**
     * 转换为backAuthorizedUris
     */
    private Set<String> toBackAuthorizedUris(List<AuthorityDO> userAuthorities) {
        if (CollUtil.isEmpty(userAuthorities)) {
            return Collections.emptySet();
        }
        Set<String> set = userAuthorities.stream()
                // 每一个relateBackUris通过,分隔多个后端uri
                .map(AuthorityDO::getRelateBackUris)
                .filter(StringUtils::isNotBlank)
                .flatMap(relateBackUris -> Arrays.stream(relateBackUris.split(CommonConstants.COMMA)))
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        return set;
    }

    /**
     * 查询用户拥有的权限信息
     */
    private List<AuthorityDO> queryUserAuthorities(Long userId) {
        List<AuthorityDO> retList = new ArrayList<>();
        List<Long> roleIds = linkUserRoleService.listRoleIdByUserId(userId);
        if (CollUtil.isEmpty(roleIds)) {
            return retList;
        }
        // 查询权限id列表
        Set<Long> authorityIds = linkRoleAuthorityService.listAuthorityIdByRoleIds(roleIds);
        if (CollUtil.isEmpty(authorityIds)) {
            return retList;
        }
        // 通过权限id列表查询出权限集合
        List<AuthorityDO> authorities = authorityService.listByIds(authorityIds);
        if (CollUtil.isEmpty(authorities)) {
            return retList;
        }
        // 因为角色分配权限时,保存的只是子节点的权限id,所有需要递归找到父级
        fillParent(authorities,retList);
        return retList;
    }

    private void fillParent(List<AuthorityDO> authorities, List<AuthorityDO> retList) {
        // key:权限id value:id对应的权限
        Map<Long, AuthorityDO> map = authorities.stream()
                .collect(Collectors.toMap(AuthorityDO::getId, Function.identity(), (a1, a2) -> a2));
        for (AuthorityDO authority : authorities) {
            recursivePutParent(authority,map,retList);
        }
    }

    /**
     * 递归找到authority的父级,一直找到parentId=-1的祖先
     */
    private void recursivePutParent(AuthorityDO authority, Map<Long, AuthorityDO> map, List<AuthorityDO> retList) {
        retList.add(authority);
        Long parentId = authority.getParentId();
        if (!CommonConstants.TOP_PARENT_ID.equals(parentId) && map.get(parentId)  == null) {
            // map没有,需要查出来这个父级并且放到map和retList中
            AuthorityDO parent = authorityService.getById(parentId);
            map.put(parent.getId(),parent);
            if (!CommonConstants.TOP_PARENT_ID.equals(parent.getParentId())) {
                recursivePutParent(parent,map,retList);
            }else {
                retList.add(parent);
            }
        }
    }
}




